package cn.mazexal.exambg.services;

import cn.hutool.core.util.IdUtil;
import cn.mazexal.exambg.common.models.BizException;
import cn.mazexal.exambg.common.models.PagedData;
import cn.mazexal.exambg.common.models.PagedQry;
import cn.mazexal.exambg.dataware.*;
import cn.mazexal.exambg.models.bo.CustomerError;
import cn.mazexal.exambg.models.converter.ExamQuestionConverter;
import cn.mazexal.exambg.models.converter.ExamQuestionMaterialsConverter;
import cn.mazexal.exambg.models.converter.ReportQuestionConverter;
import cn.mazexal.exambg.models.converter.TagConverter;
import cn.mazexal.exambg.models.db.*;
import cn.mazexal.exambg.models.qry.MaterialQry;
import cn.mazexal.exambg.models.qry.QuestionQry;
import cn.mazexal.exambg.models.redisKeys.RedisCommonKey;
import cn.mazexal.exambg.models.redisKeys.RedisTableIdKey;
import cn.mazexal.exambg.models.vo.*;
import com.alibaba.fastjson2.JSON;
import io.netty.util.internal.StringUtil;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author: Mazexal
 * Date: 2025/5/15
 */
@Service
public class QuestionService {

    @Resource
    private ExamQuestionMapper examQuestionMapper;

    @Resource
    private ExamQuestionConverter examQuestionConverter;

    @Resource
    private ExamService examService;

    @Resource
    private QuestionTagMapper questionTagMapper;

    @Resource
    private TagMapper tagMapper;

    @Resource
    private TagConverter tagConverter;

    @Resource
    private CommonService commonService;

    @Resource
    private ExamQuestionMaterialsMapper examQuestionMaterialsMapper;

    @Resource
    private ExamQuestionMaterialsConverter examQuestionMaterialsConverter;

    @Resource
    private RedisService redisService;

    @Resource
    private ExamQuestionRelationshipMapper examQuestionRelationshipMapper;

    @Resource
    private ReportQuestionMapper reportQuestionMapper;

    @Resource
    private ReportQuestionConverter reportQuestionConverter;

    public PagedData<ExamQuestionVO> getQuestionList(QuestionQry qry) {
        if (qry.getMenuId() != null && qry.getMenuId() > 0) {
            qry.setSubMenuIds(commonService.getSubMenuIds(qry.getMenuId(), qry.getExamBankId()));
        }
        List<ExamQuestionDO> list = examQuestionMapper.selectExamQuestionList(qry);
        int total = examQuestionMapper.selectExamQuestionCount(qry);
        List<ExamQuestionVO> voList = warpExamQuestionVoList(list, qry.getExamBankId());
        return PagedData.of(qry, total, voList);
    }


    List<ExamQuestionVO> warpExamQuestionVoList(List<ExamQuestionDO> examQuestionDOList, Long examBankId) {
        List<ExamQuestionVO> res = examQuestionDOList.stream().map(examQuestionConverter::toView).toList();
        List<Long> questionIds = examQuestionDOList.stream().map(ExamQuestionDO::getId).toList();
        Map<Long, List<TagVO>> tagsByQuestionIds = getTagsByQuestionIds(questionIds, examBankId);
        for (ExamQuestionVO item : res) {
            item.setQuestionExtraInfoVO(JSON.parseObject(item.getExtraInfo(), QuestionExtraInfoVO.class));
            item.setTags(tagsByQuestionIds.getOrDefault(item.getId(), new ArrayList<>()));
            item.setTagNames(item.getTags().stream().map(TagVO::getTagName).collect(Collectors.joining(",")));
        }
        return res;
    }

    public Map<Long, List<TagVO>> getTagsByQuestionIds(List<Long> questionIds, Long examBankId) {
        if (CollectionUtils.isEmpty(questionIds)) {
            return Collections.emptyMap();
        }
        List<QuestionTagDO> questionTagDOList = questionTagMapper.selectByQuestionIds(questionIds, examBankId);
        if (CollectionUtils.isNotEmpty(questionTagDOList)) {
            Set<Long> tagIds = new HashSet<>();
            questionTagDOList.forEach(questionTagDO -> tagIds.add(questionTagDO.getTagId()));
            if (CollectionUtils.isNotEmpty(tagIds)) {
                Map<Long, TagVO> tagVOMap = getTagMap(tagIds);
                Map<Long, List<TagVO>> res = new HashMap<>();
                questionTagDOList.forEach(questionTagDO -> {
                    List<TagVO> tmp = res.getOrDefault(questionTagDO.getQuestionId(), new ArrayList<>());
                    tmp.add(tagVOMap.get(questionTagDO.getTagId()));
                    res.put(questionTagDO.getQuestionId(), tmp);
                });
                return res;
            }
        }
        return new HashMap<>();
    }

    public Map<Long, TagVO> getTagMap(Collection<Long> tagIds) {
        List<TagDO> tagDOList = tagMapper.selectBatchIds(tagIds);
        List<TagVO> tagVOList = tagDOList.stream().map(tagConverter::toView).toList();
        return tagVOList.stream().collect(
                HashMap::new,
                (map, tagVO) -> map.put(tagVO.getId(), tagVO),
                Map::putAll
        );
    }

    public boolean checkAnswerFormatter(String input) {
        if (StringUtils.isEmpty(input)) {
            return false;
        }
        input = input.trim();
        if (input.length() == 1) {
            // 检查是否是大写英文字母
            return input.matches("[A-Z]");
        }
        if (input.length() > 0) {
            String[] arr = input.split(",");
            if (arr.length == 1) {
                return false;
            }
            for (String s : arr) {
                if (!s.matches("[A-Z]")) {
                    return false;
                }
            }
        }
        return true;
    }

    public ExamQuestionVO getQuestion(Long id) {
        return examQuestionConverter.toView(examQuestionMapper.selectById(id));
    }

    public void checkQuestion(ExamQuestionVO examQuestionVO) {
        // 检查问题答案是否合法
        if (examQuestionVO.getQuestionType() == 1 || examQuestionVO.getQuestionType() == 2) {
            if (!checkAnswerFormatter(examQuestionVO.getAnswer())) {
                throw new BizException(new CustomerError("10001", "答案格式错误"));
            }
        }
        // 检查menuId类型
        CardMenuDO menu = commonService.getCardMenuById(examQuestionVO.getMenuId());
        if (menu == null) {
            throw new BizException(new CustomerError("500", "菜单不存在"));
        }
        if (menu.getMenuType() != 2) {
            throw new BizException(new CustomerError("500", "菜单类型错误,只能选取文件形式菜单"));
        }
    }


    public Boolean addQuestion(ExamQuestionVO examQuestionVO) {
        // 检查问题答案是否合法
        checkQuestion(examQuestionVO);

        ExamPageVO examPage = examService.getExamPage(examQuestionVO.getExamId());
        ExamQuestionDO db = examQuestionConverter.toDb(examQuestionVO);
        db.setQuestionFrom(examPage.getName());
        db.setIsDel(0);
        db.setId(IdUtil.getSnowflakeNextId());
        // 处理tags
        handlerTags(examQuestionVO);
        examQuestionMapper.insert(db);

        // 处理与试题的关系
        ExamQuestionRelationshipDO relationship = new ExamQuestionRelationshipDO();
        relationship.setId(IdUtil.getSnowflakeNextId());
        relationship.setQuestionId(db.getId());
        relationship.setExamId(examQuestionVO.getExamId());
        relationship.setSortNum(examQuestionVO.getSortNum());
        examQuestionRelationshipMapper.insert(relationship);
        return true;
    }

    public void handlerTags(ExamQuestionVO questionVO) {
        if (StringUtils.isNotBlank(questionVO.getTagNames())) {
            Long examBankId = questionVO.getExamBankId();
            String[] tags = questionVO.getTagNames().split(",");
            Set<String> tagSet = new HashSet<>();
            for (String tag : tags) {
                tagSet.add(tag);
            }
            List<TagDO> tagList = tagMapper.getTagByNames(Arrays.asList(tags), examBankId);
            if (CollectionUtils.isEmpty(tagList)) {
                // 防止返回null，这里返回一个空list
                tagList = new ArrayList<>();
            }
            if (tagList.size() != tags.length) {
                List<TagDO> tagListForInsert = new ArrayList<>();
                for (TagDO tagDO : tagList) {
                    tagSet.remove(tagDO.getTagName());
                }
                for (String tagName : tagSet) {
                    TagDO tagDO = new TagDO();
                    tagDO.setTagName(tagName);
                    tagDO.setExamBankId(examBankId);
                    tagListForInsert.add(tagDO);
                }
                if (CollectionUtils.isNotEmpty(tagListForInsert)) {
                    tagMapper.insert(tagListForInsert);
                }
            }
            // 第二次读取, 应该是能全部获取到了
            tagList = tagMapper.getTagByNames(Arrays.asList(tags), examBankId);
            // 先清空所有的tag关联
            questionTagMapper.deleteByQuestionId(questionVO.getId(), examBankId);
            List<QuestionTagDO> questionTagDOList = new ArrayList<>();
            for (TagDO tagDO : tagList) {
                QuestionTagDO questionTagDO = new QuestionTagDO();
                questionTagDO.setId(IdUtil.getSnowflakeNextId());
                questionTagDO.setQuestionId(questionVO.getId());
                questionTagDO.setTagId(tagDO.getId());
                questionTagDO.setExamBankId(examBankId);
                questionTagDOList.add(questionTagDO);
            }
            // 然后插入数据
            questionTagMapper.insert(questionTagDOList);
        }
    }


    public Boolean updateQuestion(ExamQuestionVO examQuestionVO) {
        checkQuestion(examQuestionVO);
        ExamQuestionDO examQuestionDO = examQuestionConverter.toDb(examQuestionVO);
        if (!examQuestionVO.getExamId().equals(examQuestionDO.getExamId())) {
            ExamPageVO examPage = examService.getExamPage(examQuestionDO.getExamId());
            examQuestionDO.setQuestionFrom(examPage.getName());
        }
        handlerTags(examQuestionVO);
        ExamQuestionRelationshipDO relationship =
                examQuestionRelationshipMapper.getByBothId(examQuestionVO.getExamId(), examQuestionDO.getId());
        relationship.setSortNum(examQuestionVO.getSortNum());
        examQuestionRelationshipMapper.updateById(relationship);
        return examQuestionMapper.updateById(examQuestionDO) > 0;
    }

    public Boolean deleteQuestion(Long id) {
        ExamQuestionDO examQuestionDO = examQuestionMapper.selectById(id);
        examQuestionDO.setIsDel(1);
        examQuestionMapper.updateById(examQuestionDO);
        examQuestionRelationshipMapper.deleteByQuestionId(id, examQuestionDO.getExamId());
        return true;
    }

    public Boolean addMaterial(ExamQuestionMaterialsVO materialVO) {
        ExamQuestionMaterialsDO db = examQuestionMaterialsConverter.toDb(materialVO);
        String key = RedisTableIdKey.MATERIAL_ID;
        db.setId(redisService.getIncreaseId(key));
        db.setCreateTime(System.currentTimeMillis());
        examQuestionMaterialsMapper.insert(db);
        return true;
    }

    public Boolean updateMaterial(ExamQuestionMaterialsVO materialVO) {
        ExamQuestionMaterialsDO db = examQuestionMaterialsConverter.toDb(materialVO);
        examQuestionMaterialsMapper.updateById(db);
        return true;
    }

    public Boolean deleteMaterial(Long id) {
        return examQuestionMaterialsMapper.deleteById(id) > 0;
    }

    public PagedData<ExamQuestionMaterialsVO> getMaterialList(MaterialQry qry) {
        int count = examQuestionMaterialsMapper.selectMaterialCount(qry);
        List<ExamQuestionMaterialsDO> list = examQuestionMaterialsMapper.selectMaterialList(qry);
        return PagedData.of(qry, count, list.stream().map(examQuestionMaterialsConverter::toView).toList());
    }

    public PagedData<ReportQuestionVO> getReportQuestionList(PagedQry qry) {
        int count = reportQuestionMapper.getReportQuestionListCount(qry);
        List<ReportQuestionDO> list = reportQuestionMapper.getReportQuestionList(qry);
        return PagedData.of(qry, count, list.stream().map(reportQuestionConverter::toView).toList());
    }

    public Boolean handleReportQuestion(Long id) {
        return reportQuestionMapper.handleReportQuestion(id) > 0;
    }
}
